/*
 * Created on 2006-6-8
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package com.powerunion.datacollection.report.excelreport.datasource;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import com.powerunion.datacollection.report.excelreport.IQueryDataListener;
import com.powerunion.datacollection.report.excelreport.Logger;
import com.powerunion.datacollection.report.excelreport.base.element.Variable;
import com.powerunion.datacollection.report.excelreport.config.DataSourceConfig;


/**
 * 数据源基类, 实现一些数据源的基本功能, 如数据集的遍历,
 * 事件监听器的设置和触发等如查询监听器的设置和触发等功能.
 * @author juny
 */
public abstract class BaseDataSource implements IDataSource{
    private static Logger log = Logger.getLogger(BaseDataSource.class);
    private String name;
    
    /**
     * 
     */
    public BaseDataSource(){
        params = new HashMap();
    }
    
    /**
     * 根据指定配置信息，和数据源名称构造一个数据源对象。
     * @param config 数据源配置信息。
     * @param name 数据源名称
     */
    public BaseDataSource(DataSourceConfig config, String name){
        setConfigInfo(config, name);
        params = new HashMap();
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#setConfigInfo(excel.report.config.DataSourceConfig, java.lang.String)
     */
    public final void setConfigInfo(DataSourceConfig config, String name){
        this.config = config;
        this.name = name;
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#getName()
     */
    public String getName(){
        return this.name;
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#getConfig()
     */
    public final DataSourceConfig getConfig(){
        return this.config;
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#setParameter(java.lang.String, java.lang.Object)
     */
    public final void setParameter(String param, Object value){
        params.put(param, value);
    }
    
    /*
     * (non-Javadoc)
     * @see excel.report.datasource.IDataSource#queryData()
     */
    public final int queryData() throws Exception {
        //装载输入参数
        loadInitParams();
        
        boolean needQuery = true;
        int queryResult = IDataSource.QUERY_FAILURE;
        if(null != queryListener){
            //调用查询监听器检索数据
            if(queryListener.beforeQuery(this)){
                //如果查询监听器返回值跳过默认查询则直接返回
                needQuery = false;
            }
        }
        
        //调用实现类检索数据
        if(needQuery){
            queryResult = query(params);
        }
        
        if(null != queryListener){
            //调用查询后处理监听器
            queryListener.afterQuery(this);
        }
        
        return queryResult;
    }
    
    /**
     * 继承类重载该函数来实现数据源数据的检索, 所有继承至BaseDataBase的数据源都必须
     * 重载该函数，来实现数据检索工作。
     * @param param
     * @return
     * @throws Exception
     */
    public int query(Map param)throws Exception {
        //返回检索数据失败, 因此继承函数必须重载该
        //函数否则数据检索不会成功.
        return IDataSource.QUERY_FAILURE;
    }
    
    /**
     * 初始化，并取得数据源的输入参数. 该输入参数可能是一个字段变量，也可能是一个
     * 输入参数，还有可能是一个常量
     * @throws Exception
     */
    private final void loadInitParams() throws Exception{
        Object variable = null, tempObj = null;
        boolean resetParam = false;

        String temp = "", value = "";
        Map paramsInit = getParamInit();
        List configParams = getConfig().getParams();
        
        if(null != paramsInit && null != params){
            //已经配置配置过参数则清除掉原来的参数
            if(params.size() > 0){
                params.clear();
            }
            
            if(paramsInit.size() != configParams.size()){
                log.warn("The initialial parameters are not equal the datasource config parameters! 2");
            }
            
            //取得配置输入参数的值，该输入参数可能是一个字段变量，也可能是一个
            //输入参数，还有可能是一个常量
            for(int i=0; i<configParams.size(); i++){
                variable = paramsInit.get((String)configParams.get(i));
	            if(null != variable){
	                String fieldValue = null;
	                if(variable instanceof Variable){
	                    tempObj = ((Variable)variable).getString();
	                    if(null != tempObj){
	                        fieldValue = tempObj.toString();
	                    }
	                }else{
	                    log.error("In BaseDataSource.getParam();[" + (String)configParams.get(i) + "] Unknown parameter define.");
	                }
	                
	                if(null != fieldValue){
	                    this.setParameter((String)configParams.get(i), fieldValue);
	                }
	            }
            }
        }
    }
    
    /**
     * 设置该数据源实例的输入参数取值配置信息。信息保存方式为：(key=数据源对应的输入参数名称, value=参数值取值配置)
     * <br>因为如果某个数据源在其定义过程中如果配置了相应的参数信息，
     * 当系统在生成具体的某个报表时使用到了该数据源，这是候必须在配置文件中引用该数据源，同时也必须配置
     * 该数据源实例的输入参数配置信息，即告诉该数据源实例，当它需要输入参数时应该去从那获得参数的值。
     * 该配置通过< param-init >节点来定义，例如：<br>
     * < datasource name="s5" source="testDataSource2"><br>
     * < param-init name="arg1" value="$P{argumentName}"/ ><br>
     * < /datasource><br>
     * 在上面的配子文件中配置了一个名为s5的数据源的输入参数的配置信息，
     * 其表示数据源其有一个名为arg1的输入参数应该去用户请求报表参数列表中取名称为
     * argumentName的参数值。
     * @param paramInit 初始化输入参数配置信息。
     */
    public final void setParamInit(Map paramInit){
        //拷贝参数到本地，不能直接引用，应为在具体的数据源中会修改
        //paramsInit中保存的初始化参数信息，会将初始化变量替换成相应的
        //变量对象
        if(null != paramInit){
            this.paramsInit = new HashMap(paramInit);
        }
    }
    
    /**
     * 取得数据输入参数参数配置信息。在<param-init>节点配置
     * @return 返回配置信息列表，
     */
    public final Map getParamInit(){
        return paramsInit;
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#moveToFirst()
     */
    public boolean moveToFirst(){
        if(null != recordList && recordList.size() > 0){
            index = 0;
            return true;
        }
        return false;
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#next()
     */
    public Map next(){
        if(null == recordList) return null;
        
        if(index + 1 < recordList.size() && recordList.size() > 0){
            return (Map)recordList.get(++index);
        }else{
            //modified by ajun 2006-07-10 修改查询会漏掉一条记录的问题。
            index++;
            return null;
    	}
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#hasNext()
     */
    public boolean hasNext() {
        if(null == recordList || index == -1){
            return false;
        }
        //modified by ajun 2006-07-10 修改查询会漏掉一条记录的问题。
        //这里不好改MoveToFirst（）函数，因为系统要求默认就在第一条记录。
        //return ((index + 1) < data.size()) ? true : false;
        return ((index + 1) <= recordList.size()) ? true : false;
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#undoNext()
     */
    public void undoNext(){
        if(index > 0){
            index--;
        }else{
            //throw new Exception(Out of rang of the datasoure);
        }
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#getString(java.lang.String)
     */
    public String getString(String fieldName){
        if(null == recordList) return "";
        
        Object value = this.getValue(fieldName);
        if(null != value){
            return value.toString();
        }
        
        return "";
    }
    
    /**
     * 取得数据源当前记录指定字段的值，
     * @param fieldName	字段名称
     * @param applyListener	<br>
	 * 				true 启用字段取值事件监听器; <br>
	 * 				false 不启用字段取值事件监听器。
     * @return 非空：返回字段值；
     * 		<br>null：字段或字段值不存在。
     */
    public Object getValue(String fieldName, boolean applyListener) {
        if(checkIndexSafe()){
            Map curRecord = (Map)recordList.get(index);
            if(null == curRecord) return null;
            
            Object originalValue = curRecord.get(fieldName);
            Object retValue = getFieldListenerValue(fieldName, originalValue);
            if((null == originalValue) || (retValue != null)){
                //没取到则直接返回FieldListener中的值
                //如果FieldListener中有值，则优先返回该值。
                return retValue;
            }else{
                //FieldListener没有返回值，则直接返回Map中取得的值。
                return originalValue;
            }
        }
        return null;
    }
    
    /* (non-Javadoc)
     * @see excel.report.datasource.IDataSource#getValue(java.lang.String)
     */
    public Object getValue(String fieldName) {
        return getValue(fieldName, true);
    }
    
    /**
     * 取得当前记录的map, 调用该函数数据源会返回一个封装了当前记录的map对象。
     * @return	成功：返回当前封装了当前记录集的map对象。 <br>
     * 			失败：返回空（当前数据源为空或数据源游标处于记录集合的末尾）
     */
    public Map getCurRecord(){
        if(checkIndexSafe()){
            return (Map)recordList.get(index);
        }
        return null;
    }
    
    /**
     * 取得字段取值监听器返回的字段值。
     * @param fieldName 监听的字段名称
     * @param value 字段原始值
     * @return 返回监听函数返回的值
     */
    private final Object getFieldListenerValue(String fieldName, Object value){
        if(null == fieldListener){
            return null;
        }
        
        String[] fields = fieldListener.getFields();
        Object retValue = null;
        
        if(null == fields){
            retValue = fieldListener.getValue(this, fieldName, value);
        }else{
	        for(int i=0; i<fields.length; i++){
	            if(fields[i].equalsIgnoreCase(fieldName)){
	                retValue = fieldListener.getValue(this, fieldName, value);
	                break;
	            }
	        }
        }
        
        return retValue;
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#size()
     */
    public int size(){
        return recordList == null ? 0 : recordList.size();
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#getParams()
     */
    public final Map getParams(){
        return params;
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#getFieldType(java.lang.String)
     */
    public String getFieldType(String fieldName){
        return (String)config.getFields().get(fieldName);
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSourceListener#setQueryDataListener(excel.report.IQueryDataListener)
     */
    public final boolean setQueryDataListener(IQueryDataListener listener){
        if(null != listener){
            this.queryListener = listener;
            return true;
        }
        return false;
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSourceListener#setFieldListener(excel.report.datasource.IFieldListener)
     */
    public final boolean setFieldListener(IFieldListener listener){
        if(null != listener){
            this.fieldListener = listener;
            return true;
        }
        return false;
    }
    
    /*
     *  (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    public String toString(){
        return this.getClass().getName();
    }
    
    /**
     * 初始化数据源记录集。调用该函数会丢掉数据源中原有的数据集。
     * @param capacity
     */
    public void initializeDataSourceCapacity(int capacity){
        if(null == recordList){
            recordList = new ArrayList(capacity);
        }else{
            recordList.clear();
            ((ArrayList)recordList).ensureCapacity(capacity);
        }
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#getType()
     */
    public String getType(){
        return "";
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#initialize()
     */
    public boolean initialize() throws Exception{
        return true;
    }
    
    /*
     *  (non-Javadoc)
     * @see excel.report.datasource.IDataSource#destroy()
     */
    public void destroy()throws Exception{
        ;
    }
    
    /**
     * 添加字段数据.向当前记录中添加一个字段数据。
     * @param field 字段名称。
     * @param value 字段数据值
     * @return true 数据添加成功； false 数据添加失败。
     */
    public boolean addField(String field, Object value){
        if(null != field && null != value){
            if(null == tempRecord){
                tempRecord = new HashMap();
            }
            tempRecord.put(field, value);
            return true;
        }
        return false;
    }
    
    /**
     * 修改数据源对象中当前记录的指定字段值。如果传入的字段不存在函数返回false。
     * 否则函数会将数据源对象当前记录集的字段值修改为value传入的值。
     * @param fieldName	要修改值的字段名称
     * @param value		字段的新的值。
     * @return			true：修改成功  false 修改失败
     */
    public boolean setFieldValue(String fieldName, Object value){
        if(null == fieldName || "".equals(fieldName) || null == value){
            return false;
        }
        
        if(checkIndexSafe()){
            Map curRecord = (Map)recordList.get(index);
            Object fieldValue = curRecord.get(fieldName);
            if(null == fieldValue){
                return false;
            }
            curRecord.put(fieldName, value);
            return true;
        }
        
        return false;
    }
    
    /**
     * 在数据源中插入一条新记录.调用该操作后，会将先前插入的所有字段值作为一条记录插入到数据源中。
     * @return true 记录添加成功； false 记录添加失败。
     */
    public boolean addRecord(){
        if(null != tempRecord){
            this.addRecord(tempRecord);
            tempRecord = new HashMap();
            return true;
        }
        return false;
    }
    private Map tempRecord = null;
    
    /**
     * 加入一条新的记录到数据源
     * @param map 记录集合Map
     * @return 返回是否成功。true 成功， false 失败。
     */
    public boolean addRecord(Map map){
        if(null == this.recordList){
            recordList = new ArrayList();   
        }
        
        recordList.add(map);
        return true;
    }
    
    /**
     * 将一个List保存的记录集添加到数据源中，其中list 保存的是Map对象。
     * 每个Map对象保存一条记录。map中数据的存放格式
     * key=fieldName(字段名称)  value=fieldValue(字段值)
     * @param list
     */
    public final void setRecordList(List list){
        recordList = list;
        this.moveToFirst();
    }
    
    /**
     * 取得数据源数据迭代器对象。
     */
    public Iterator iterator() {
       return new Iterator(){
           public void remove() {
               if(null != recordList){
                   if(checkIndexSafe()){
                       recordList.remove(index);
                       if(index > 0){
                           index --;
                       }
                   }
               }
           }

           public boolean hasNext() {
               if(null == recordList) return false;
               
               if(checkIndexSafe()){
                   if(index < recordList.size()){
                       return true;
                   }
               }
               return false;
           }

           public Object next() {
               if(null == recordList || recordList.size()<1 ) throw new NoSuchElementException("Datasource is empty! [" + getName() + "]");
               if(checkIndexSafe()){
                   return recordList.get(index++);
               }
               throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
           }
       };
        
    }
    
    private boolean checkIndexSafe(){
        if(index < recordList.size() && recordList.size() > 0){
            return true;
        }        
        return false;
    }
    
    //保存当前记录游标.
    private int index = 0;
    //保存数据源配置文件
    private DataSourceConfig config = null;
    //保存数据源参数
    private Map params = null;
    //保存数据查询监听器
    private IQueryDataListener queryListener = null;
    //保存字段监视对象。
    private IFieldListener fieldListener = null;
    //保存记录数据列表.
    protected List recordList = null;
    //保存数据源参数初始化配子信息
    private Map paramsInit = null;
    
}
